'''我的字符串加密解密类,是加密解密的方法合集.
   所有要加密的字符串认定为utf-8编码.
   加密后的字符串,md5,sha1,sha256由库函数hexdigest()生成;
   AES加密后的字节流则由base64重新编码再用utf-8解码,保证能用字符串方式传输字节流;
'''

import hashlib
import base64

from Crypto.Cipher import AES

## 类定义
class StringCrypt:

    def __init__(self):
        self.AES_KEYLEN = 16 # AES加密的字节流密钥长度规定
        return
        
    ## sha256加密,加密后长度为64
    def sha256(self,srcString):
        cipher = hashlib.sha256() # 加密器
        cipher.update(srcString.encode('utf-8'))
        result = cipher.hexdigest()
        return result
     
    ## sha1加密,加密后长度为40
    def sha1(self,srcString):
        cipher = hashlib.sha1() # 加密器
        cipher.update(srcString.encode('utf-8'))
        result = cipher.hexdigest()
        return result
        
    ## md5加密,加密后长度为32
    def md5(self,srcString):
        cipher = hashlib.md5() # 加密器
        cipher.update(srcString.encode('utf-8'))
        result = cipher.hexdigest()
        return result    
        
    ## AES加密,模式为EAX,key为密码字符串,会被改成长度16的字节流
    def AESCrypt(self,srcString,key):
        srcBytes = srcString.encode('utf-8') # 要加密的字节流数据   
        #srcBytes = base64.b64encode(srcString.encode('utf-8')) # 要加密的字节流数据  
        keyBytes = key.encode('utf-8') # 密码字节流
        # 太短则补0,太长则截断,最后长度为KEYLEN
        if len(keyBytes) < self.AES_KEYLEN:
            keyBytes = keyBytes + b'0'*(self.AES_KEYLEN-len(keyBytes))
        else:
            keyBytes = keyBytes[0:self.AES_KEYLEN]
        ## 加密过程
        # 生成加密解密器对象cipher
        cipher = AES.new(keyBytes, AES.MODE_EAX) 
        # 加密字节流,以及与keyBytes同长度的tagBytes,tagBytes要写入加密文件的.
        cipherBytes, tagBytes = cipher.encrypt_and_digest(srcBytes) 
        # 使用一次的随机字节流,用于填充加密文件开头,增加解密难度,长度与keyBytes一样
        nonceBytes = cipher.nonce 
        # 加密后的字节流
        secretDataBytes = nonceBytes+tagBytes+cipherBytes
        # 返回的字符串,重新计算出secretDataBytes的方法为:
        # base64.b64decode(result.encode('utf-8'))
        # base64的编码是把一个字节流变成一个只有0-127组成的字节流
        result = base64.b64encode(secretDataBytes).decode('utf-8')
        return result
    
    ## AES解密,模式为EAX,key为密码字符串,会被改成长度16的字节流
    def AESDecrypt(self,secretString,key):
        # 加密字节流
        secretBytes =  base64.b64decode(secretString.encode('utf-8'))
        keyBytes = key.encode('utf-8') # 密码字节流
        # 太短则补0,太长则截断,最后长度为KEYLEN
        if len(keyBytes) < self.AES_KEYLEN:
            keyBytes = keyBytes + b'0'*(self.AES_KEYLEN-len(keyBytes))
        else:
            keyBytes = keyBytes[0:self.AES_KEYLEN]       
        # 解密过程,需要从加密后的字节流读取nonceBytes,tagBytes,cipherBytes
        nonceBytes = secretBytes[0:self.AES_KEYLEN]
        tagBytes = secretBytes[self.AES_KEYLEN:self.AES_KEYLEN*2]
        cipherBytes = secretBytes[self.AES_KEYLEN*2:]
        # 生成加密解密器对象cipher,解密时指定nonce
        cipher = AES.new(keyBytes, AES.MODE_EAX, nonce = nonceBytes)
        resultBytes = cipher.decrypt_and_verify(cipherBytes, tagBytes) # 解密
        result = resultBytes.decode('utf-8')
        return result

        
if __name__ == '__main__':
    sc = StringCrypt()
    # 明文,密码
    srcString = 'HelloWorld!你好世界!こんにちは!!!'
    key = 'izumo3_suzuka世ち'
    print('明文:\n'+srcString)
    print('长度为',len(srcString))
    # AES加密解密
    AESCryptString = sc.AESCrypt(srcString,key)
    print('\nAES加密后的字符串:\n'+AESCryptString)
    print('长度为:',len(AESCryptString))
    AESDecryptString = sc.AESDecrypt(AESCryptString,key)
    print('\nAES解密后的字符串:\n'+AESDecryptString)
    # sha256加密
    sha256CryptString = sc.sha256(srcString)
    print('\nsha256加密后的字符串:\n'+sha256CryptString)
    print('长度为:',len(sha256CryptString))
    # sha1加密
    sha1CryptString = sc.sha1(srcString)
    print('\nsha1加密后的字符串:\n'+sha1CryptString)
    print('长度为:',len(sha1CryptString))
    # md5加密
    md5CryptString = sc.md5(srcString)
    print('\nmd5加密后的字符串:\n'+md5CryptString)
    print('长度为:',len(md5CryptString))